#pragma once

#include <linux/time.h>
#include <linux/jiffies.h>

/* Subtract two ktime_t variables. rem = lhs -rhs: */
#define ktime_sub(lhs, rhs) ((lhs) - (rhs))

/* Add two ktime_t variables. res = lhs + rhs: */
#define ktime_add(lhs, rhs) ((lhs) + (rhs))

/*
 * Same as ktime_add(), but avoids undefined behaviour on overflow; however,
 * this means that you must check the result for overflow yourself.
 */
#define ktime_add_unsafe(lhs, rhs) ((u64)(lhs) + (rhs))

/*
 * Add a ktime_t variable and a scalar nanosecond value.
 * res = kt + nsval:
 */
#define ktime_add_ns(kt, nsval) ((kt) + (nsval))

/**
 * ktime_compare - Compares two ktime_t variables for less, greater or equal
 * @cmp1:	comparable1
 * @cmp2:	comparable2
 *
 * Return: ...
 *   cmp1  < cmp2: return <0
 *   cmp1 == cmp2: return 0
 *   cmp1  > cmp2: return >0
 */
static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
{
    if (cmp1 < cmp2)
        return -1;
    if (cmp1 > cmp2)
        return 1;
    return 0;
}

/**
 * ktime_before - Compare if a ktime_t value is smaller than another one.
 * @cmp1:	comparable1
 * @cmp2:	comparable2
 *
 * Return: true if cmp1 happened before cmp2.
 */
static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
{
    return ktime_compare(cmp1, cmp2) < 0;
}

static inline ktime_t ns_to_ktime(u64 ns)
{
    return ns;
}

static inline s64 ktime_to_ns(const ktime_t kt)
{
    return kt;
}

static inline s64 ktime_divns(const ktime_t kt, s64 div)
{
    /*
     * 32-bit implementation cannot handle negative divisors,
     * so catch them on 64bit as well.
     */
    // WARN_ON(div < 0);
    return kt / div;
}

static inline s64 ktime_to_us(const ktime_t kt)
{
    return ktime_divns(kt, NSEC_PER_USEC);
}

static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier)
{
    return ktime_to_us(ktime_sub(later, earlier));
}

/**
 * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
 * @secs:	seconds to set
 * @nsecs:	nanoseconds to set
 *
 * Return: The ktime_t representation of the value.
 */
static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
{
	if ((secs >= KTIME_SEC_MAX))
		return KTIME_MAX;

	return secs * NSEC_PER_SEC + (s64)nsecs;
}

/*
 * Add two ktime values and do a safety check for overflow:
 */
static inline ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs)
{
    ktime_t res = ktime_add_unsafe(lhs, rhs);

    /*
     * We use KTIME_SEC_MAX here, the maximum timeout which we can
     * return to user space in a timespec:
     */
    if (res < 0 || res < lhs || res < rhs)
        res = ktime_set(KTIME_SEC_MAX, 0);

    return res;
}

#include <linux/timekeeping.h>
